/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.udt.designtime.webapi;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.das.commonmodel.util.HandleAssemblyNameUtil;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.service.MetadataService;
import com.inspur.edp.udt.designtime.api.entity.ComplexDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.UnifiedDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.element.UdtElement;
import com.inspur.edp.udt.designtime.api.extension.BaseUdtExtension;
import com.inspur.edp.udt.designtime.api.json.SimpleDataTypeDeserializer;
import com.inspur.edp.udt.designtime.api.json.SimpleDataTypeSerializer;
import com.inspur.edp.udt.designtime.api.json.UdtElementDeserializer;
import com.inspur.edp.udt.designtime.api.json.UdtElementSerializer;
import com.inspur.edp.udt.designtime.api.nocode.BusinessField;
import com.inspur.edp.udt.designtime.api.nocode.IBusinessFieldService;
import com.inspur.edp.udt.designtime.api.utils.UdtUtils;
import com.inspur.edp.udt.designtime.manager.ContentSerializer;
import com.inspur.edp.udt.designtime.manager.generatecmpcode.JavaCodeFileGenerator;
import com.inspur.edp.udt.designtime.manager.generatecomponent.ComponentGenerator;
import com.inspur.edp.udt.designtime.manager.services.UpdateAssoRefElementUtil;
import com.inspur.edp.udt.designtime.manager.services.UpdateElementService;
import io.iec.edp.caf.boot.context.CAFContext;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;

import java.util.List;
import java.util.Date;
import java.util.Map;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;

/**
 * 业务字段对外接口
 *
 * @author haoxiaofei
 */
@Path("")
@Produces(MediaType.APPLICATION_JSON)
public class UdtController {

    private final String SimpleUdtType = "SimpleDataType";
    private final String ComplexUdtType = "ComplexDataType";
    private com.inspur.edp.lcm.metadata.api.service.MetadataService metadataService;

    /**
     * 元数据服务
     *
     * @return 获取元数据服务类实例
     */
    private MetadataService getMetadataService() {
        if (metadataService == null)
            metadataService = SpringBeanUtils.getBean(MetadataService.class);
        return metadataService;
    }

    /**
     * 新建UDT元数据
     *
     * @param metadataInfo
     * @return
     */
    @Path("initial")
    @PUT
    @Produces(MediaType.APPLICATION_JSON)
    public String initial(String metadataInfo) {
        ObjectMapper mapper = new ObjectMapper();

        try {
            JsonNode node = mapper.readTree(metadataInfo);
            String type = node.get("type").textValue();
            String metadataId = node.get("metadataId").textValue();
            String metadataName = node.get("metadataName").textValue();
            String metadataCode = node.get("metadataCode").textValue();
            String metadataAssembly = node.get("metadataAssembly").textValue();

            UnifiedDataTypeDef udt = initSimpleDataTypeDef(metadataId, metadataName, metadataCode, metadataAssembly, type);
            ContentSerializer serializer = new ContentSerializer();
            String udtContentJson = serializer.Serialize(udt).toString();
            return udtContentJson;
        } catch (JsonProcessingException e) {
            throw new RuntimeException("json结构异常，导致反序列化出错，错误信息请见内部异常", e);
        }
    }

    /**
     * 初始化单值udt的类型定义
     *
     * @param metadataID 元数据ID
     * @param metadataName 元数据名称
     * @param metadataCode 元数据编号
     * @param metadataAssembly 元数据集合
     * @param type
     * @return
     */
    private UnifiedDataTypeDef initSimpleDataTypeDef(String metadataID, String metadataName, String metadataCode,
        String metadataAssembly, String type) {
        UnifiedDataTypeDef udt;
        switch (type) {
            case SimpleUdtType:
                udt = new SimpleDataTypeDef();
                break;
            case ComplexUdtType:
                udt = new ComplexDataTypeDef();
                break;
            default:
                throw new RuntimeException("未能识别当前UDT类型，当前类型为" + type);
        }

        udt.setID(metadataID);
        udt.setCode(metadataCode);
        udt.setName(metadataName);
        // todo : cef runime 引用
//    udt.setCreatedDate(Date.from(CAFContext.current.getCurrentDateTime().toInstant()));
//    udt.setModifiedDate(Date.from(CAFContext.current.getCurrentDateTime().toInstant()));
        // 20190902-wj-恢复删除初始化时AssemblyName属性上的".udt." + udt.Code
        udt.setDotnetAssemblyName(metadataAssembly + ".udt." + udt.getCode());
        //udt.AssemblyName = metadataAssembly;
        return udt;
    }

    /**
     * 更新UDT关联信息
     *
     * @param info
     * @return
     */
    @Path("updateUdtAsso")
    @PUT
    @Produces(MediaType.APPLICATION_JSON)
    public boolean updateUdtAsso(String info) {
        ObjectMapper mapper = new ObjectMapper();

        try {
            JsonNode node = mapper.readTree(info);
            String fileName = node.get("fileName").textValue();
            String path = node.get("path").textValue();
            GspMetadata metadata = getMetadataService().loadMetadata(fileName, path);
            UpdateAssoRefElementUtil.getInstance().handleUdtAssos(metadata);

            getMetadataService().saveMetadata(metadata, UdtUtils.getCombinePath(path, metadata.getHeader().getFileName()));
            return true;
        } catch (JsonProcessingException e) {
            throw new RuntimeException("json结构异常，导致反序列化出错，错误信息请见内部异常", e);
        }
    }

    /**
     * 处理单值UDT关联
     *
     * @param metadataInfo
     * @return
     */
    @Path("handleSUdtAsso")
    @PUT
    @Produces(MediaType.APPLICATION_JSON)
    public String handleSUdtAsso(String metadataInfo) {
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.addDeserializer(UnifiedDataTypeDef.class, new SimpleDataTypeDeserializer());
        module.addSerializer(UnifiedDataTypeDef.class, new SimpleDataTypeSerializer());
        mapper.registerModule(module);
        try {
            JsonNode node = mapper.readTree(metadataInfo);
            String elementJson = node.get("elementJson").textValue();
            SimpleDataTypeDef sUdt = mapper.readValue(elementJson, SimpleDataTypeDef.class);
            UpdateElementService.getInstance().UpdateSUdtAssos(sUdt);

            String eleJson = mapper.writeValueAsString(sUdt);
            return eleJson;
        } catch (JsonProcessingException e) {
            throw new RuntimeException("json结构异常，导致反序列化出错，错误信息请见内部异常", e);
        }
    }

    /**
     * 处理多值UDT上的关联
     *
     * @param metadataInfo
     * @return
     */
    @Path("handleCUdtAsso")
    @PUT
    @Produces(MediaType.APPLICATION_JSON)
    public String handleCUdtAsso(String metadataInfo) {
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.addSerializer(IGspCommonField.class, new UdtElementSerializer());
        module.addDeserializer(IGspCommonField.class, new UdtElementDeserializer());
        mapper.registerModule(module);
        try {
            JsonNode node = mapper.readTree(metadataInfo);
            String elementJson = node.get("elementJson").textValue();

            UdtElement udtElement = (UdtElement) mapper.readValue(elementJson, IGspCommonField.class);
            UpdateElementService.getInstance().UpdateFieldWithAsso(udtElement);
            String udtEleJson = mapper.writeValueAsString(udtElement);
            return udtEleJson;
        } catch (JsonProcessingException e) {
            throw new RuntimeException("json结构异常，导致反序列化出错，错误信息请见内部异常", e);
        }
    }

    /**
     * 新建UDT元数据或者打开已有元数据
     *
     * @param metadataInfo
     * @return
     */
    @Path("handleElements")
    @PUT
    @Produces(MediaType.APPLICATION_JSON)
    public boolean handleElements(String metadataInfo) {
        ObjectMapper mapper = new ObjectMapper();

        try {
            JsonNode node = mapper.readTree(metadataInfo);
            String fileName = node.get("fileName").textValue();
            String path = node.get("path").textValue();
            GspMetadata metadata = getMetadataService().loadMetadata(fileName, path);

            UnifiedDataTypeDef udt = (UnifiedDataTypeDef) metadata.getContent();

            if (udt instanceof SimpleDataTypeDef) {
                UpdateElementService.getInstance().HandleSUdtElements((SimpleDataTypeDef) udt);
            } else if (udt instanceof ComplexDataTypeDef) {
                UpdateElementService.getInstance().HandleCUdtElements((ComplexDataTypeDef) udt);
            }
            getMetadataService().saveMetadata(metadata, UdtUtils.getCombinePath(path, fileName));

            return true;

        } catch (JsonProcessingException e) {
            throw new RuntimeException("json结构异常，导致反序列化出错，错误信息请见内部异常", e);
        }
    }

    /**
     * UDT元数据的保存并同步
     *
     * @param metadataInfo
     */
    @Path("publish")
    @PUT
    @Produces(MediaType.APPLICATION_JSON)
    public void publish(String metadataInfo) {
        ObjectMapper mapper = new ObjectMapper();

        try {
            JsonNode node = mapper.readTree(metadataInfo);
            String path = node.get("path").textValue();
            String metadataName = node.get("name").textValue();
            GspMetadata metadata = getMetadataService().loadMetadata(metadataName, path);
            String bizObjectID = metadata.getHeader().getBizobjectID();
            ComponentGenerator.getInstance().generateComponent((UnifiedDataTypeDef) metadata.getContent(), path, bizObjectID);

            new JavaCodeFileGenerator(metadata).JavaGenerate();
            getMetadataService().saveMetadata(metadata, UdtUtils.getCombinePath(path, metadata.getHeader().getFileName()));

        } catch (JsonProcessingException e) {
            throw new RuntimeException("json结构异常，导致反序列化出错，错误信息请见内部异常", e);
        }
    }

    /**
     * 单值/多值UDT元数据上选择udt类型
     *
     * @param metadataInfo
     * @return
     */
    @Path("chooseUdt")
    @PUT
    @Produces(MediaType.APPLICATION_JSON)
    public String chooseUdt(String metadataInfo) {
        ObjectMapper mapper = new ObjectMapper();

        try {
            JsonNode node = mapper.readTree(metadataInfo);
            String refUdtId = node.get("refUdtId").textValue();
            String path = node.get("path").textValue();
            String udtElementJson = node.get("udtElementJson").textValue();
            return UpdateElementService.getInstance().updateElementWithRefUdt(refUdtId, path, udtElementJson);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("json结构异常，导致反序列化出错，错误信息请见内部异常", e);
        }
    }

    /**
     * 单值/多值UDT获取ConfigId
     *
     * @param generatingAssembly
     * @return
     */
    @Path("generatedConfigId")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public String getGeneratedConfigId(@QueryParam("generatingAssembly") String generatingAssembly)
        throws JsonProcessingException {
        if (generatingAssembly == null || generatingAssembly.isEmpty()) {
            return "";
        }
        return new ObjectMapper()
            .writeValueAsString(HandleAssemblyNameUtil.convertToJavaPackageName(generatingAssembly));
    }

    @Path("businessFields")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public List<BusinessField> getBusinessField() {
        IBusinessFieldService businessFieldService = SpringBeanUtils.getBean(IBusinessFieldService.class);
        return businessFieldService.getBusinessFields();
    }

    @Path("extendInfos")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Map<String, BaseUdtExtension> getBusinessFieldExtendInfos(
        @QueryParam("businessFieldId") String businessFieldId) {
        IBusinessFieldService businessFieldService = SpringBeanUtils.getBean(IBusinessFieldService.class);
        BusinessField businessField = businessFieldService.getBusinessField(businessFieldId);
        return businessField.getUnifiedDataTypeDef().getUdtExtensions();
    }

    /**
     * 通过业务种类ID获取业务字段
     *
     * @param categoryId
     * @return
     */
    @Path("businessFieldsByCategoryId")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public List<BusinessField> getBusinessField(@QueryParam("categoryId") String categoryId) {
        IBusinessFieldService businessFieldService = SpringBeanUtils.getBean(IBusinessFieldService.class);
        return businessFieldService.getBusinessFieldsByCategoryId(categoryId);
    }

    /**
     * 业务字段保存接口
     *
     * @param businessField
     */
    @Path("businessField/singleasso")
    @PUT
    @Produces(MediaType.APPLICATION_JSON)
    public void saveBusinessField(BusinessField businessField) {
        IBusinessFieldService businessFieldService = SpringBeanUtils.getBean(IBusinessFieldService.class);
        businessFieldService.saveBusinessField(businessField);
    }
}
